library ieee;
use ieee.std_logic_1164.all;
use IEEE.NUMERIC_STD.all;
use work.typeDefinitions.all;

entity cpuCore is
  port (
    -- clock signal
    CLK      : in  std_logic;
    -- reset for processor
    nReset   : in  std_logic;
    -- halt for processor
    halt     : out std_logic;
    -- default PC for this CPU
    defaultPC		: in	std_logic_vector(31 downto 0);
    -- mem signals
		memAddr      : out std_logic_vector(15 downto 0);  -- mem address being read/written
		memWriteData : out std_logic_vector(31 downto 0);  -- mem data to be written
		memWEN       : out std_logic;     -- write enable
		memREN       : out std_logic;     -- read enable
		memReadData  : in  std_logic_vector(31 downto 0);  -- mem data to be read
		memState     : in  std_logic_vector(1 downto 0);    -- state of mem
    -- coherency BS
    TxBusOp   : out memBusOp;
		TxBusAddr : out std_logic_vector(31 downto 0);
		TxBusResp : out memBusResp;
		TxBusData : out std_logic_vector(63 downto 0);
		RxBusOp   : in  memBusOp;
		RxBusAddr : in  std_logic_vector(31 downto 0);
		RxBusResp : in  memBusResp;
		RxBusData : in  std_logic_vector(63 downto 0)
	);

end cpuCore;

architecture cpuCore_arch of cpuCore is

  component cpuPipeline
    port (
      clk    : in std_logic;
      nReset : in std_logic;

      dMemDataR : in  std_logic_vector(31 downto 0);
      dMemWait  : in  std_logic;
      dMemRen   : out std_logic;        --!!!!!!!!!!!!!!!!!!!!!!!
      dMemDataW : out std_logic_vector(31 downto 0);
      dMemAddr  : out std_logic_vector(31 downto 0);
      dMemWen   : out std_logic;

      iMemWait : in  std_logic;
      iMemAddr : out std_logic_vector(31 downto 0);  --need more signals?
      iMemData : in  std_logic_vector(31 downto 0);
      iMemRen  : out std_logic;

      defaultPC : in std_logic_vector(31 downto 0);

      halt : out std_logic;

      forwardIn  : in  forwardSignalsIn;
      forwardOut : out forwardSignalsOut;
			
			-- LINK REGISTER
			linkWen		: out	std_logic; 
			linkAddr	: out std_logic_vector(31 downto 0);
			linkLock	: in std_logic_vector(31 downto 0);
			
      instruction : out interStageOperation;
      hold        : in  stageHoldSignals;
      invalidate  : in  stageInvalidateSignals
     );
  end component;

  component StallLogic is
    port
      (
        nReset       : in  std_logic;
        icacheWait   : in  std_logic;
        dcacheWait   : in  std_logic;
        hold         : out stageHoldSignals;
        instructions : in  interStageOperation;
        invalidate   : out stageInvalidateSignals;
        forwardIn    : in  forwardSignalsOut
       );
  end component;

  component ForwardingLogic
    port
      (
        forwardIn    : in  forwardSignalsOut;
        forwardOut   : out forwardSignalsIn;
        instructions : in  interStageOperation
       );
  end component;

	-- memory hierarchy
	component memHierarchy
  	port 
  		(
				--normal stuff
				clk    : in std_logic;
				nReset : in std_logic;
		
				--dcache
				halt          : in  std_logic;
				halt_out      : out std_logic;
				dMemRead      : in  std_logic;                       -- CPU side
				dMemWrite     : in  std_logic;                       -- CPU side
				dMemWait      : out std_logic;                       -- CPU side
				dMemAddr      : in  std_logic_vector (31 downto 0);  -- CPU side
				dMemDataRead  : out std_logic_vector (31 downto 0);  -- CPU side
				dMemDataWrite : in  std_logic_vector (31 downto 0);  -- CPU side
						
				--icache
				iMemData : out std_logic_vector(31 downto 0);
				iMemRen  : in  std_logic;
				iMemWait : out std_logic;
				iMemAddr : in  std_logic_vector (31 downto 0);
		
				TxBusOp   : out memBusOp;
				TxBusAddr : out std_logic_vector(31 downto 0);
				TxBusResp : out memBusResp;
				TxBusData : out std_logic_vector(63 downto 0);
				RxBusOp   : in  memBusOp;
				RxBusAddr : in  std_logic_vector(31 downto 0);
				RxBusResp : in  memBusResp;
				RxBusData : in  std_logic_vector(63 downto 0);
		
				--linkreg
				lockAddr : in  std_logic_vector(31 downto 0);
				lockWEN  : in  std_logic;
				busOp    : in  memBusOp;
				busAddr  : in  std_logic_vector(31 downto 0);
				lockOut  : out std_logic_vector(31 downto 0);
		
				--"memory" side
				memAddr      : out std_logic_vector(15 downto 0);  -- mem address being read/written
				memWriteData : out std_logic_vector(31 downto 0);  -- mem data to be written
				memWEN       : out std_logic;     -- write enable
				memREN       : out std_logic;     -- read enable
				memReadData  : in  std_logic_vector(31 downto 0);  -- mem data to be read
				memState     : in  std_logic_vector(1 downto 0)    -- state of mem
			);
	end component;

  signal instructionCache, dataCache : cacheSignal;
  signal mem                                     : memSignal;
	
	signal coherenceBus : dcacheBus;
	
	signal link : linkRegIO;

  signal instruction : interStageOperation;
  signal hold        : stageHoldSignals;
  signal invalidate  : stageInvalidateSignals;

  signal forward : forwardSignals;
                        
  signal t_halt : std_logic;
                        
--signal forward : forwardSignals;
                        
begin  -- cpuCore_arch

  memAddr   		<= mem.addr;
  memWriteData	<= mem.wData;
  memWEN    		<= mem.wEn;
  memREN    		<= mem.rEn;
  mem.rData 		<= memReadData;
  mem.state 		<= memState;

  instructionCache.wEN   <= '0';
  instructionCache.wData <= (others => '0');

  forw_c : ForwardingLogic port map (
    forwardIn    => forward.outs,
    forwardOut   => forward.ins,
    instructions => instruction
	);

  stall_c : StallLogic port map (
    nReset       => nReset,
    icacheWait   => instructionCache.stall,
    dcacheWait   => dataCache.stall,
    hold         => hold,
    instructions => instruction,
    invalidate   => invalidate,
    forwardIn    => forward.outs
	);

  cpu_c : cpuPipeline port map (
    clk       => clk,
    nReset    => nReset,
    dMemDataR => dataCache.rData,
    dMemWait  => dataCache.stall,
    dMemRen   => dataCache.rEn,
    dMemDataW => dataCache.wData,
    dMemWen   => dataCache.wEn,
    dMemAddr  => dataCache.addr,

    iMemData => instructionCache.rData,
    iMemRen  => instructionCache.rEn,
    iMemWait => instructionCache.stall,
    iMemAddr => instructionCache.addr,

    forwardIn  => forward.ins,
    forwardOut => forward.outs,
		
		-- LINK REGISTER
		linkWen		=> link.WEN,
		linkAddr	=> link.cpuAddr,
		linkLock	=> link.lockAddr,
		
    defaultPC => defaultPC,

    halt        => t_halt,
    instruction => instruction,
    hold        => hold,
    invalidate  => invalidate
	);
	
		memHier_c : memHierarchy port map (
			--normal stuff
			clk    				=> clk,
			nReset				=> nReset,
	
			--dcache
			halt          => t_halt,	-- cpu final halt
			halt_out      => halt,		-- FINAL FINAL HALT
			dMemRead      => dataCache.rEn,
			dMemWrite     => dataCache.wEn,
			dMemWait      => dataCache.stall,
			dMemAddr      => dataCache.addr,
			dMemDataRead  => dataCache.rData,
			dMemDataWrite => dataCache.wData,
			
			--icache
			iMemData			=> instructionCache.rData,
			iMemRen				=> instructionCache.rEn,
			iMemWait			=> instructionCache.stall,
			iMemAddr			=> instructionCache.addr,
			
			-- coherence BS
			TxBusOp				=> coherenceBus.TxOp,		  
			TxBusAddr			=> coherenceBus.TxAddr,
			TxBusResp			=> coherenceBus.TxResp,
			TxBusData			=> coherenceBus.TxData, 
			RxBusOp				=> coherenceBus.RxOp,		  
			RxBusAddr			=> coherenceBus.RxAddr, 
			RxBusResp			=> coherenceBus.RxResp, 
			RxBusData			=> coherenceBus.RxData, 
	
			--linkreg
			lockAddr			=> link.cpuAddr,
			lockWEN    		=> link.WEN,
			busOp      		=> link.busOp,
			busAddr       => link.busAddr,
			lockOut       => link.lockAddr,
			
			--"memory" side
			memAddr       => mem.addr,     
			memWriteData  => mem.wData,
			memWEN        => mem.wEn,      
			memREN        => mem.rEn,      
			memReadData   => mem.rData, 
			memState      => mem.state    
		);
		
		-- connect link register to bus
		link.busOp <= RxBusOp;
		link.busAddr <= RxBusAddr;
		
		-- connect Bus To bus record
		TxBusOp <= coherenceBus.TxOp;
		TxBusAddr <= coherenceBus.TxAddr;
		TxBusResp <= coherenceBus.TxResp;
		TxBusData <= coherenceBus.TxData;
		coherenceBus.RxOp <= RxBusOp;
		coherenceBus.RxAddr <= RxBusAddr;
		coherenceBus.RxResp <= RxBusResp;
		coherenceBus.RxData <= RxBusData;

end cpuCore_arch;
